#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include "convert_bond.h"
#define steps 400
#include "yield_curve.h"
#include "maximum.h"


Convert_bond::Convert_bond(){
	days_in_year = 365;
	underPrice = 50;
	vol = .2;
	strike = 120;
	strike2 = 70;
	interest = .06;
	days = 365;
	current_value=0;
	dividend_rate=0;
	maturity = days/days_in_year;
	conversion_ratio = 2;
	notional=100; 
	put_value = 0;
	bond_value = 0;
	conversion_intrinsic_value = 0;}

	void Convert_bond::compute() {
  	   double dt;
	   double u;
	   double d;
	   double p;
	   double disc;
	   int i;
	   int j;
	   double temp;
	   double temp1;
	   double temp2;
	   double temp3;
	   double St[steps][steps]; //first "steps" = period no., 2nd steps = values per period
	   double Convertible[steps][steps];
 	   double conversion_value[steps][steps];
	   double put[steps][steps];
	   double pure_bond[steps][steps];
	   double risky_discount_factor[steps][steps];

	   //precompute constants
	 

	   dt = (days/days_in_year)/steps;
	   u = exp(((interest-dividend_rate-pow(vol,2))*dt)+vol*sqrt(dt));
	   //	printf("u is %10.5f\n", u);
	   d = exp(((interest-dividend_rate-pow(vol,2))*dt)-vol*sqrt(dt));
	   //	printf("d is %10.5f\n", d);
	   p = (exp((interest-dividend_rate)*dt)-d)/(u-d);
        //	printf("p is %10.5f\n", p);
        disc= exp(-interest*dt);
	
	   //initialize asset prices

	   for (i = 0; i < steps; i++)
	   {
		St[i][0] = underPrice*pow(d,i);
		temp = maximum((underPrice-St[i][0])/underPrice,0);
		temp1 = interest+(temp/3);
		risky_discount_factor[i][0] = exp(-temp1*dt);
		// printf("St[i][j] is %10.5f, %10i, 0\n", St[i][0],i);
		for ( j = 1; j <= i; j++ )
		{
		St[i][j] = St[i][j-1]*(u/d);
		// printf("St[i][j] is %10.5f, %10i, %10i\n", St[i][j],i,j);
		temp = maximum((underPrice-St[i][j])/underPrice,0);
		temp1 = interest+(temp/3);
		risky_discount_factor[i][j] = exp(-temp1*dt);
//		printf("risky_discount_factor[i][j] is %10.5f.\n", risky_discount_factor[i][j]);
		}
	   }

	   for ( j = 0; j <= steps-1; j++ )
	   {
		if (St[steps-1][j]*conversion_ratio> notional)
		{
		   conversion_value[steps-1][j] = St[steps-1][j]*conversion_ratio;
		   pure_bond[steps-1][j] = 0;
		   put[steps-1][j] = 0;
		}
		else if (strike2>notional)
		{
		   conversion_value[steps-1][j] = 0;
 		   pure_bond[steps-1][j] = 0;
		   put[steps-1][j] = strike2;
		}
		else
		{
	         conversion_value[steps-1][j] = 0; 
		   pure_bond[steps-1][j] = notional; 
		   put[steps-1][j] = 0;
		}
		Convertible[steps-1][j] = conversion_value[steps-1][j]+put[steps-1][j]+pure_bond[steps-1][j];
		//printf("conversion_value[steps-1][j],put[steps-1][j],pure_bond[steps-1][j],St[steps-1][j] are %10.5f,%10.5f,%10.5f,%10.5f.\n", conversion_value[steps-1][j],put[steps-1][j],pure_bond[steps-1][j],St[steps-1][j]);
	   }
	   
		//step back through the tree applying early exercise condition

	   for ( i = steps-2; i >= 0; i--)	
	   {
		for ( j = 0; j <= i; j++ )
		{

		   temp = p*pure_bond[i+1][j+1]*risky_discount_factor[i][j];
		   temp1 = (1-p)*pure_bond[i+1][j]*risky_discount_factor[i][j];
		   pure_bond[i][j] = temp + temp1;

	         temp = p*(conversion_value[i+1][j+1]*disc);
		   temp1 = (1-p)*(conversion_value[i+1][j]*disc);
		   conversion_value[i][j] = temp + temp1;

		   temp = p*put[i+1][j+1]*disc;
 		   temp1 = (1-p)*(put[i+1][j])*disc;
		   put[i][j] = temp + temp1;

	         Convertible[i][j] = pure_bond[i][j] + conversion_value[i][j] + put[i][j];
	//	   printf("conversion_value[i][j],put[i][j],pure_bond[i][j],St[i][j],risky_discount_factor[i][j],i&j are %10.5f,%10.5f,%10.5f,%10.5f,%10.5f,%4i,%4i.\n", conversion_value[i][j],put[i][j],pure_bond[i][j],St[i][j],risky_discount_factor[i][j],i,j);
		
		   if (St[i][j]*conversion_ratio> Convertible[i][j]) // conversion by choice
		   {
		      conversion_value[i][j] = St[i][j]*conversion_ratio;
			pure_bond[i][j] = 0;
			put[i][j] = 0;
		   }

		   else if (Convertible[i][j]>strike && Convertible[i][j]>St[i][j]*conversion_ratio) // forced conversion	
		   {
			conversion_value[i][j] = St[i][j]*conversion_ratio;
			pure_bond[i][j] = 0;
			put[i][j] = 0;
		   }

		   else if (strike2>Convertible[i][j]) //put
		   {
		      put[i][j] = strike2;
			pure_bond[i][j] = 0;
			conversion_value[i][j] = 0;
		   }

		   //Convertible[i][j] = pure_bond[i][j] + conversion_value[i][j] + put[i][j];
		//   printf("conversion_value[i][j],put[i][j],pure_bond[i][j],St[i][j],risky_discount_factor[i][j],i&j are %10.5f,%10.5f,%10.5f,%10.5f,%10.5f,%4i,%4i.\n", conversion_value[i][j],put[i][j],pure_bond[i][j],St[i][j],risky_discount_factor[i][j],i,j);
		}
	   }
		current_value = pure_bond[0][0] + conversion_value[0][0] + put[0][0];
		put_value = put[0][0];
		bond_value = pure_bond[0][0];
		conversion_intrinsic_value = conversion_value[0][0];
		//current_value = Convertible[0][0];
	}

	void Convert_bond::setUnderlyingValue(double u1)
	{
		underPrice = u1;
	}
	void Convert_bond::setVol (double vly1)
	{
		vol = vly1;
	}
	void Convert_bond::setStrike(double sk)
	{
		strike = sk;
	}
	void Convert_bond::setInterest(double i)
	{
		interest = i;
	}
	void Convert_bond::setTimeToMaturity(double Ttt)
	{
		days = Ttt;
	}
	void Convert_bond::setDividendRate(double div)
	{
		dividend_rate = div;
	}
	void Convert_bond::setStrike2(double sk_2)
	{
		strike2 = sk_2;
	}
	void Convert_bond::setConversionRatio(double ratio)
	{
		conversion_ratio = ratio;
	}
	void Convert_bond::setNotional(double yyy)
	{
		notional = yyy;
	}
	void Convert_bond::printInputs()
	{
		printf("Notional is %5.5f.\n", notional);
		printf("Underlying price is %5.5f.\n", underPrice);
		printf("Strike of issuer call is %5.5f.\n", strike);
		printf("Strike of put is %5.5f.\n", strike2);
		printf("Conversion Ratio is %5.5f shares per 1 bond\n", conversion_ratio);
		printf("Volatility is %5.5f.\n", vol);
		printf("Interest rate is %5.5f.\n", interest);
		printf("Days to maturity are %5.5f.\n", days);
		printf("No. of steps applied was %4i.\n", steps);
		printf("Continuous dividend yield is %5.5f.\n", dividend_rate); 
	}

	double Convert_bond::getFairValue()
	{
	return current_value;
	}
	double Convert_bond::getBondValue()
	{
	return bond_value;
	}
	double Convert_bond::getPutValue()
	{
	return put_value;
	}
	double Convert_bond::getConversionValue()
	{
	return conversion_intrinsic_value;
	}
	double Convert_bond::getParity()
	{
	return conversion_ratio*underPrice;
	}
	double Convert_bond::getParity_Delta()
	{
		double original_value;
		double new_value;
		double original_parity = conversion_ratio;
		if (current_value == 0)
		{
		compute();
		}
		original_value = current_value;
		conversion_ratio = conversion_ratio+conversion_ratio*.001;
		compute();
		conversion_ratio = original_parity;
		new_value = current_value;
		current_value = original_value;
		return (new_value - original_value)/(conversion_ratio*.001);
	}
	double Convert_bond::getInterest_Rate_Delta()
	{
		double original_value;
		double new_value;
		double original_int;
		original_int = interest;
		if (current_value == 0)
		{
		compute();
		}
		original_value = current_value;
		interest = interest+(interest*.001);
		compute();
		interest = original_int;
		new_value = current_value;
		current_value = original_value;
		return ((new_value - original_value)/(interest*.001))/100; // in % points
	}
	double Convert_bond::getParityGamma()
	{
		double original_value;
		double orginal_parity_delta;
		double original_parity = conversion_ratio;
		double adjusted_Parity_Delta;
		if (current_value == 0)
		{
		compute();
		}
		orginal_parity_delta = getParity_Delta();
		original_value = current_value;
		conversion_ratio = conversion_ratio+conversion_ratio*.001;
		compute();
		adjusted_Parity_Delta = getParity_Delta();
		conversion_ratio = original_parity;
		current_value = original_value;
		return (adjusted_Parity_Delta - orginal_parity_delta)/(conversion_ratio*.001);
	}



